﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace UDPclient
{
    public partial class ClientForm : Form
    {
        private ServerInfo server;
        private IPEndPoint receiverEndPoint;
        private UdpClient client;
        private Dictionary<byte, Color> clientsColor;
        private Color brushColor;
        private SolidBrush brush;
        private Bitmap image;
        private bool isDrawingEnabled;
        private Thread receiverThread;

        public ClientForm()
        {
            InitializeComponent();

            client = new UdpClient();
            clientsColor = new Dictionary<byte, Color>();
            brushColor = Color.Black;
            brush = new SolidBrush(brushColor);
            image = new Bitmap(pictureBox.Width, pictureBox.Height);
            isDrawingEnabled = false;
            disconnectButton.Enabled = false;
            pictureBox.Enabled = false;
        }

        private void colorButton_Click(object sender, EventArgs e)
        {
            colorDialog.ShowDialog();
            brushColor = this.colorDialog.Color;
            brush.Color = brushColor;
        }

        private void connectButton_Click(object sender, EventArgs e)
        {
            IPAddress ip;
            int port;
            if (IPAddress.TryParse(IPAdressTextBox.Text, out ip) && Int32.TryParse(portTextBox.Text, out port))
            {
                server = new ServerInfo(new IPEndPoint(ip, port));
                String message = "CONNECT";
                byte[] datagram = Encoding.UTF8.GetBytes(message);
                client.Send(datagram, datagram.Length, server.senderEndPoint);

                receiverThread = new Thread(ReceiveData);
                receiverThread.Start();
            }
        }

        private void pictureBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDrawingEnabled)
            {
                int[] point = new int[2] { e.X, e.Y };
                byte[] datagram = new byte[point.Length * sizeof(int)];
                Buffer.BlockCopy(point, 0, datagram, 0, datagram.Length);
                client.Send(datagram, datagram.Length, server.receiverEndPoint);
            }
        }

        private void pictureBox_MouseDown(object sender, MouseEventArgs e)
        {
            isDrawingEnabled = true;
            byte[] datagram = BitConverter.GetBytes(brushColor.ToArgb());
            client.Send(datagram, datagram.Length, server.receiverEndPoint);
        }

        private void pictureBox_MouseUp(object sender, MouseEventArgs e)
        {
            isDrawingEnabled = false;
        }

        private void ReceiveData()
        {
            while (true)
            {
                try
                {
                    byte[] datagram = client.Receive(ref receiverEndPoint);
                    if (datagram.Length == 4)
                    {
                        server.receiverEndPoint = receiverEndPoint;
                        server.receiverEndPoint.Port = BitConverter.ToInt32(datagram, 0);
                        statusTextBox.Invoke((MethodInvoker)(() => 
                        {
                            statusTextBox.Text = "connected";
                            connectButton.Enabled = false;
                            disconnectButton.Enabled = true;
                            pictureBox.Enabled = true;
                        }));
                        
                    }
                    else if (datagram.Length == 5)
                    {
                        if (!clientsColor.ContainsKey(datagram[4]))
                        {
                            clientsColor.Add(datagram[4], Color.FromArgb(BitConverter.ToInt32(datagram, 0)));
                        }
                        else
                        {
                            clientsColor[datagram[4]] = Color.FromArgb(BitConverter.ToInt32(datagram, 0));
                        }
                    }
                    else if (datagram.Length == 9)
                    {
                        Draw(datagram);
                    }
                }
                catch (SocketException ex)
                {
                    MessageBox.Show(ex.Message, "Błąd połączenia", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void Draw(byte[] data)
        {
            int[] point = new int[2];
            Buffer.BlockCopy(data, 0, point, 0, data.Length - 1);
            Color c;
            if (clientsColor.TryGetValue(data[8], out c))
            {
                brush = new SolidBrush(c);
                pictureBox.Invoke((MethodInvoker)(() =>
                {
                    pictureBox.Image = image;
                    Graphics graphics = Graphics.FromImage(pictureBox.Image);
                    graphics.FillEllipse(brush, point[0], point[1], 5, 5);
                }
                ));
            }
        }

        private void disconnectButton_Click(object sender, EventArgs e)
        {
            String message = "DISCONNECT";
            byte[] datagram = Encoding.UTF8.GetBytes(message);
            client.Send(datagram, datagram.Length, server.senderEndPoint);
            statusTextBox.Text = "disconnected";
            pictureBox.Enabled = false;
            connectButton.Enabled = true;
            disconnectButton.Enabled = false;
        }
    }
}
